Connector amb la PICA




Important

El connector amb la PICA de Canigó utilitza Java 1.5 (veure Requeriments)

 A partir de la versió 2.3.9 del framework el connector genèric a la pica adopta el nou versionat de connectors (independent del framework), per tant per incloure el connector a la pica caldrà fer-ho amb la versió 1.0:

 <dependency>
<groupId>canigo.connectors</groupId>
<artifactId>canigo-connectors-pica</artifactId>
<version>1.0</version>
</dependency>


Introducció

Propòsit

El propòsit del connector és proporcionar una interfície java per accedir a la PICA.

El connector amb la PICA disposa de dos tipus de comunicació, un d'ells a través de web service síncron, i l'altre, mitjançant web service asíncron.

Context i Escenaris d'Ús

El connector PICA es troba dins els connectors de serveis funcional.

Versions i Dependències

En el present apartat es mostren quines són les versions i dependències necessàries per fer ús del Servei.

Les dependències descrites a la següent url són requerides per tal de fer funcionar el servei:
Dependències Connector amb PICA

A l'incloure la dependència del connector en el projecte, podreu veure que s'afegeixen dues llibreries anomenades client-pica-2.3.2.jar i api-pica-2.3.2.jar. Aquestes llibreries són dependències directes del connector amb la PICA de Canigó i han estat desenvolupades per l'OT PICA. L'OT Canigó ha empaquetat aquestes llibreries i s'han publicat al repositori, dins el package canigo.connectors.

Qualsevol dubte/consulta respecte funcionalitats, documentació, etc. d'aquestes llibreries, us podeu adreçar a l'OT PICA: oficinapica.ctti@gencat.cat

A qui va dirigit

Aquest document va dirigit als següents perfils:

  1. Programador. Per conéixer l'ús del connector.
  2. Arquitecte. Per conéixer quins són els components i la configuració del connector.

Documents i Fonts de Referència

[1] Guia d'ús de l'API de comunicació amb la PICA - Projecte: P070085-OTPICA
[2] Missatgeria PICA (P060025-PICA > PD2 > Fase I > Missatgeria PICA > P060025-PICA-PD2-DTE-V05.3.Missatgeria PICA_pdf.pdf)
[3] Oficina Tècnica PICA oficinapica.ctti@gencat.cat

Glossari

  • PICA: Plataforma d'Integració i Col.laboració Administrativa
  • TER: Temps Estimat de Resposta

Descripció Detallada

Arquitectura i Components

Interfícies i Components Genèrics

Es pot trobar tota la documentació JavaDoc i el codi font referent aquests components a les següents urls:

JavaDoc: http://canigo.ctti.gencat.net/confluence/canigodocs/site/canigo2_3_9/canigo-connectors-root/canigo-connectors-pica/apidocs/index.html
Codi Font:  http://canigo.ctti.gencat.net/confluence/canigodocs/site/canigo2_3_9/canigo-connectors-root/canigo-connectors-pica/xref/index.html

Requeriments

El connector amb la PICA de Canigó, ha estat desenvolupat amb Java 1.5, degut a requeriments tècnics que venien establerts. Per tant, es pot utilitzar el connector si s'està desenvolupant amb aquesta versió. En canvi, si s'està treballant amb versions anteriors, s'ha de realitzar la comunicació amb la PICA de forma directa. Per a més informació podeu adreçar-vos directament a l'Oficina Tècnica de la PICA (oficinapica.ctti@gencat.cat).

Instal.lació i Configuració

Instal.lació

La instal.lació del connector requereix de la utilització de la llibreria 'canigo-connectors-pica' i les dependències indicades a l'apartat 'Introducció-Versions i Dependències'.

La instal.lació es realitza seguint el procediment habitual per components/serveis Canigó.

És necessari tenir accés a la intranet de la Generalitat per poder fer proves i/o utilitzar-lo.

Pel que fa a les dependències, n'hi ha dues que s'han de descarregar manualment:

Una alternativa és descarregar-se els artefactes i ubicar-los en els packages indicats, amb la particularitat que el axis2-ant-plugin, ha de tenir el nom: axis2-ant-plugin-1.3-maven-plugin.jar.

Configuració

Primer de tot, s'ha de crear una estructura de directoris a qualsevol ubicació dins el classpath del projecte, per exemple dins de "resources". L'estructura de directoris ha de ser com segueix:
- Crear un directori anomenat "axis2client"
- Dins d'aquest directori crear-ne dos més: "conf" i "modules".
- Descarregar-se els següents fitxers:

Tot seguit mostrem gràficament l'estructura de directoris amb els fitxers inclosos:



És necessari un fitxer de configuració Spring a la pròpia aplicació, en el qual es defineixen les dades necessàries per a realitzar una correcta comunicació amb la PICA (requeridor, producte, configuració SSL -si s'escau-, etc.).

Fitxer de configuració: picaServiceConfiguration.xml
Ubicació proposada: <PROJECT_ROOT>/src/main/resources/spring

<beans>
   <bean name="ProducteModalitatBase" abstract="true"
	class="cat.gencat.pica.peticio.core.beans.ProducteModalitat">
	   <property name="passwordType" value="PasswordText"/>
   </bean>

   <bean id="requeridor" class="cat.gencat.pica.peticio.core.beans.Requeridor" singleton="true">
        <property name="fitxerSignatura" value="signatura.properties"/>
        <property name="idSolicitante" value="ID_SOL"/>
	<property name="idTransmision" value="ID_TRANS"/>
	<property name="nombreSolicitante" value="SOL"/>
	<property name="password" value="PSW"/>
	<property name="user" value="USER"/>
   </bean>

   <bean id="PicaCanigoService" class="cat.gencat.testpica.prova.PicaServiceWrapper" singleton="false">
        <!-- és requerit que s'indiqui aquest valor per axisDefinition -->
	<property name="axisDefinition" value="classpath:axis2client/" />

 	<!-- configuració SSL (opcional) -->
	<property name="trustStoreSSLKeystore" value="certificats/cert.jks" />
	<property name="trustStoreSSLKeystoreType" value="JKS" />
	<property name="trustStoreSSLKeystorePassword" value="password" />

	<property name="loggingService" ref="loggingService"/>
	<property name="requeridor" ref="requeridor"/>
	<property name="modalitats">
 	  <map>
	    <entry key="KEY_MODALITAT">
	      <bean parent="ProducteModalitatBase">
		 <property name="signat" value="false"/>
		 <property name="urlPICA" value="http://preproduccio.pica.gencat.intranet/
                         pica_cataleg/AppJava/services/PADRO_MUNICIPI_RESIDENCIA"/>
		 <property name="codCertificado" value="COD_CERT"/>
    		 <property name="codProducto" value="COD_PRODUCTE"/>
  	         <property name="finalidad" value="FIN"/>
 	 	 <property name="nifEmisor" value="NNNNNNNNX"/>
 		 <property name="nombreEmisor" value="DEP. D'ACCIO SOCIAL I CIUTADANIA"/>
 	      </bean>
 	    </entry>
	  </map>
	</property>
   </bean>

   <bean id="loggingConfigurator" class="net.gencat.ctti.canigo.services.logging.log4j.xml.HostDOMConfigurator"
       init-method="init">
	<property name="configFileName">
 	   <value>classpath:log4j-test.xml</value>
	</property>
   </bean>

   <bean id="loggingService" class="net.gencat.ctti.canigo.services.logging.log4j.Log4JServiceImpl"
      init-method="init">
	<property name="configurator">
	   <ref local="loggingConfigurator" />
	</property>
   </bean>
</beans>

Els beans definits en aquest fitxer són:

  • PicaCanigoService: correspon a la classe embolcall PicaServiceWrapper, que és l'encarregada d'invocar als serveis de la PICA. Conté el servei de log de Canigó, el requeridor i un map de modalitats, que conté els productes que es volen consumir contra la PICA. També s'inclou la informació necessària per a la comunicació HTTPS, si es vol utilitzar.
  • Requeridor: Conté les dades relacionades amb el requeridor que vol consumir un producte/modalitat de la PICA. A partir de la versió 2.3.6 del connector, s'afegeix la possibilitat de poder modificar el requeridor i per tant, no s'obliga a tenir el mateix a totes les instàncies del servei, per fer-ho possible hem de configurar el bean del servei com a no singleton, tal i com es pot comprovar a l'exemple de més a dalt.
  • ProducteModalitat (definits dins el map de modalitats): Conté les dades relacionades amb el producte i la modalitat que es vol consumir: codi del producte i la modalitat (codi de certificat), finalitat, URL de la PICA a la que es vol atacar, etc.

Els valors introduïts a cadascuna de les propietats dels beans han de correspondre amb les dades pertanyents al producte/modalitat que es vol consumir, dades de l'emissor, etc.

L'únic valor requerit és el que es defineix per a la propietat de la definició d'Axis (dins el bean PicaCanigoService):

<property name="axisDefinition" value="classpath:axis2client/"/>


Important

Si l'aplicació ha de ser desplegada en format empaquetat (.war, .ear) caldrà indicar la ubicació de la carpeta de configuració d'axis 2 com a Path absolut dins el servidor on desplegarà. Caldrà acordar aquest Path amb els responsables del CPD on anirà desplegada l'aplicació.
Exemple:

<property name="axisDefinition" value="file:/export/AppJavaDades/int/.../axis2client/"/>


D'altra banda, l'atribut fitxerSignatura del bean Requeridor, correspon a un fitxer de propietats que tindrà definides les dades del certificat:

Fitxer de propietats: signatura.properties
Ubicació proposada: <PROJECT_ROOT>/src/main/resources

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
#org.apache.ws.security.crypto.merlin.file=certificats.p12
#org.apache.ws.security.crypto.merlin.keystore.type=PKCS12
org.apache.ws.security.crypto.merlin.file=certificats.jks
org.apache.ws.security.crypto.merlin.keystore.type=JKS
org.apache.ws.security.crypto.merlin.keystore.password=CANIGO
#org.apache.ws.security.crypto.merlin.keystore.provider=SunJSSE
org.apache.ws.security.crypto.merlin.keystore.provider=SUN
org.apache.ws.security.crypto.merlin.keystore.alias=CANIGO
org.apache.ws.security.crypto.merlin.alias.password=CANIGO



Finalment, cal incloure la dependència amb el connector a l'arxiu de configuració Maven2 del projecte (pom.xml):
<dependency>
    <groupId>canigo.connectors</groupId>
    <artifactId>canigo-connectors-pica</artifactId>
    <version>2.3.2</version>
</dependency>

La versió de Canigó 2.3.2 és la primera en la qual es publica el connector amb la PICA, que correspon a la darrera release del framework. Per tant, a mida que es vagin publicant versions, s'haurà de modificar el nombre de versió indicat en el pom.xml.

Utilització del Servei

Funcions PICA

La utilització del Connector es basa principalment en la configuració. L'ús directe des dels clients es permet mitjançant la intefície del servei.

Per utilitzar el servei PICA instanciarem un objecte IPicaServiceWrapper, cridant després a qualsevol dels mètodes que aquesta intefície presenta.

IPicaServiceWrapper picaServiceWrapper = (IPicaServiceWrapper)beanFactory.getBean("PicaCanigoService");
assertNotNull(picaServiceWrapper);
IPICAServiceSincron service = picaServiceWrapper.getPicaWebServiceSincronInstance("KEY_MODALITAT");
assertNotNull(service);

On KEY_MODALITAT correspondrà a la clau del producte/modalitat definit en el map de modalitats que es troba al fitxer de configuració.
Tot seguit, mostrarem les funcionalitats que incorpora aquesta interfície:
public interface IPicaServiceWrapper {

  //obtenir les instancies de ws sincron/asincron
  public abstract IPICAServiceSincron getPicaWebServiceSincronInstance(String modalitat);
  public abstract IPICAServiceAsincron getPicaWebServiceAsincronInstance(String modalitat);

  //peticio al servei de la PICA per a ws sincron/asincron
  public abstract CridaSincronaResponseDocument ferPeticioAlServei(IPICAServiceSincron serviceSincron);
  public abstract CridaAsincronaResponseDocument ferPeticioAlServei(IPICAServiceAsincron serviceAsincron);

  //extreure les dades a partir de la resposta per a ws sincron/asincron
  public abstract List<DadesEspecifiques> extreuDadesEspecifiques(IPICAServiceSincron service,
      CridaSincronaResponseDocument resposta);
  public abstract List<DadesEspecifiques> extreuDadesEspecifiques(IPICAServiceAsincron service,
      ObtindreResultatResponseDocument resposta);

  //obtenir l'estat en que es troba la peticio (nomes ws asincron)
  public abstract EstatAsincron extreuEstatPeticio(IPICAServiceAsincron serviceAsincron,
     ObtindreResultatResponseDocument resposta);

  //obtenir resultat final de la peticio (nomes ws asincron)
  public abstract ObtindreResultatResponseDocument obtenirResultatPeticio(IPICAServiceAsincron serviceAsincron);
}

Exemple d'utilització

A continuació mostrem exemples d'ús de diferents les funcionalitats que ens proporciona la interfície, tant per a peticions síncrones com asíncrones.

  • Petició WebService Síncron

public void testPicaServiceSincronWrapper() {
   try {
      IPicaServiceWrapper picaServiceWrapper =
          (IPicaServiceWrapper)beanFactory.getBean("PicaCanigoService");
      assertNotNull(picaServiceWrapper);
      IPICAServiceSincron service =
          picaServiceWrapper.getPicaWebServiceSincronInstance("KEY_MODALITAT");
      assertNotNull(picaServiceWrapper);

      //veure explicacio d'aquests metodes al final de l'exemple
      Funcionari func = creaFuncionari();
      Titular tit = creaTitular();
      List<DadesEspecifiques> datosEspecificosXML = createDadesEspecifiques();

      service.setFuncionari( func );
      service.setTitular( tit );
      service.setDadesEspecifiques( datosEspecificosXML );
      service.crearPeticio( "PROVA_OTCANIGO_" + System.currentTimeMillis() );

      //fer peticio
      CridaSincronaResponseDocument resp = picaServiceWrapper.ferPeticioAlServei(service);
      //extreure resultat
      List<DadesEspecifiques> resposta= picaServiceWrapper.extreuDadesEspecifiques(service,resp);

      if (loggingService != null) {
        Iterator<DadesEspecifiques> it = resposta.iterator();
        while (it.hasNext()) {
	   DadesEspecifiques object = it.next();
           loggingService.getLog(this.getClass()).info(object.getDadesXML());
	}
      }
    } catch (Exception e) {
       if (loggingService != null) {
          loggingService.getLog(this.getClass()).error(e.getMessage());
       }
    } finally {
       SSLConfiguration.resetSSL();
    }
 }


  • Petició WebService Asíncron

public void testPicaServiceAsincronWrapper() {
   try {
      IPicaServiceWrapper picaServiceWrapper = (IPicaServiceWrapper) beanFactory.getBean("PicaCanigoService");
      assertNotNull(picaServiceWrapper);
      IPICAServiceAsincron service = picaServiceWrapper.getPicaWebServiceAsincronInstance("KEY_MODALITAT");
      assertNotNull(service);

      //veure explicacio d'aquests metodes al final de l'exemple
      Funcionari func = creaFuncionari();
      Titular tit = creaTitular();
      List<DadesEspecifiques> datosEspecificosXML = createDadesEspecifiques();

      service.setFuncionari( func );
      service.setTitular( tit );
      service.setDadesEspecifiques( datosEspecificosXML );
      service.crearPeticio( "OTCANIGO_" + System.currentTimeMillis() );

      //fer la peticio al servei
      CridaAsincronaResponseDocument resp = picaServiceWrapper.ferPeticioAlServei(service);
      EstatAsincron estat = picaServiceWrapper.extreuEstatPeticio(service,resp);

      String codiEstat = estat.getCodiEstat();
      int ter = estat.getTempsEstimatResposta();

      if (loggingService != null) {
      	loggingService.getLog(this.getClass()).info("TER: " + ter);
        loggingService.getLog(this.getClass()).info("Estat Petició:" + codiEstat);
      }
      if (codiEstat.equals("PeticioEnProces")) {
       	Thread.sleep(new Long(estat.getTempsEstimatResposta()).longValue()*36000);
      }else {
         if (loggingService != null) {
            loggingService.getLog(this.getClass()).error("Codi estat peticio: " + codiEstat);
            loggingService.getLog(this.getClass()).error("Literal error: " + estat.getLiteralError());
         }
      }

      //obtenir resultat peticio
      ObtindreResultatResponseDocument resultat = picaServiceWrapper.obtenirResultatPeticio(service);

      //extreure resultat peticio
      List<DadesEspecifiques> llistaResultat = picaServiceWrapper.extreuDadesEspecifiques(service,resultat);

      if (loggingService != null) {
         Iterator<DadesEspecifiques> it = llistaResultat.iterator();
         while (it.hasNext()) {
	    DadesEspecifiques object = it.next();
 	    loggingService.getLog(this.getClass()).info(object.getDadesXML());
         }
      }
   } catch (WrappedCheckedException e) {
    	ExceptionDetails details = e.getExceptionDetails();
    	if (details != null) {
      	   if (loggingService != null) {
       	     loggingService.getLog(this.getClass()).error(details.getErrorMessage());
           }
    	}
   } catch (Exception e) {
    	if (loggingService != null) {
    	   loggingService.getLog(this.getClass()).error(e.getMessage());
   	}
   } finally {
	SSLConfiguration.resetSSL();
   }
}

Cal destacar que l'identificador de la petició ha de ser únic, per aquest motiu es concatena un prefix de text qualsevol amb el timestamp del sistema.
Per a més informació respecte l'especificació tècnica i funcional podeu contactar amb l'OT PICA.
En aquest exemple, els mètodes privats crearFuncionari() i crearTitular() (creats simplement per aquest test) s'encarreguen de setejar les propietats del funcionari que fa la petició i titular sobre el que es fa la petició respectivament. El mètode també privat createDadesEspecifiques() conté una llista de les sol.licituds, en format XML, que s'enviaran dins la petició.

Tot seguit mostrem un exemple del format que han de seguir les dades específiques (que depen del producte/modalitat que es vol consumir):

private List<DadesEspecifiques> createDadesEspecifiques() {

   List<DadesEspecifiques> datosEspecificosXML = new ArrayList<DadesEspecifiques>(  );
   StringBuffer sb = new StringBuffer("<ns1:request xmlns:ns1=\"http://www.gencat.net/tfn\">" );
   sb.append( "<ns1:simpleparam name=\"NUMTIT\">83746573</ns1:simpleparam>" );
   sb.append( "<ns1:simpleparam name=\"NUMNIF\">111111111H</ns1:simpleparam>" );
   sb.append( "</ns1:request>" );

   DadesEspecifiques dades = new DadesEspecifiques();
   dades.setIdSolicitud("1");
   dades.setDadesXML(sb.toString());
   datosEspecificosXML.add(dades);

   return datosEspecificosXML;
}

Dins una petició (llista de dades específiques) es poden incloure diverses sol- licituds, els identificadors de les quals han de ser únics dins una mateixa petició. Si volguéssim afegir una altra sol- licitud en l'exemple, només caldria instanciar un nou objecte DadesEspecifiques, amb IdSolicitud="2", un nou StringBuffer amb les dades i afegirlo a la llista datosEspecificosXML.

Integració amb Altres Serveis

Integració amb el Servei d'Internacionalització

En els fitxers de configuració es defineixen claus que permeten especificar quins missatges retornar en cas errors. Per a poder traduir aquestes claus és necessari especificar que el connector usarà el Servei d'Internacionalització (veure Configuració).